<?php

namespace yunj\app\admin\service\member\log;

use Jenssegers\Agent\Agent;
use think\facade\Db;
use yunj\app\admin\enum\RedisKey;
use yunj\app\admin\job\AdminMemberLogRecordJob;
use yunj\core\constants\AreaConst;
use yunj\core\constants\BuilderConst;

class LogSaveService extends Service {

    /**
     * 处理日志数据保存
     * @param array $log
     */
    public static function handle(array $log): void {
        try {
            $lock = lock("admin.log:{$log['id']}", 20);
            self::handleSaveData($log);
            Db::transaction(function () use ($log, $lock) {
                self::saveLogData($log);
                $lock->timeoutThrow();          // 判断执行是否超时 TODO 最好另外开个携程去监听执行是否超时
                self::saveLogAttrData($log);
                $lock->timeoutThrow();          // 判断执行是否超时
            });
        } catch (\Throwable $e) {
            log_exception($e, '', "admin log save fail!", ['log' => $log]);
        }
        isset($lock) && $lock->release();
    }

    /**
     * 处理保存数据
     * @param array $log
     */
    private static function handleSaveData(array &$log): void {
        // request_params
        if (($requestParams = $log['request_params'] ?? '') && !is_string($requestParams)) {
            $log['request_params'] = json_encode($requestParams, JSON_UNESCAPED_UNICODE);
        }
        // data_id
        if (!array_key_exists('data_id', $log)) {
            $log['data_id'] = self::getDefaultDataId($requestParamsData ?? []);
        }
        // response_content
        if (($responseContent = $log['response_content'] ?? '') && !is_string($responseContent)) {
            $log['response_content'] = json_encode($responseContent, JSON_UNESCAPED_UNICODE);
        }
        // ip
        $ip = $log['ip'];
        $ipProvince = '';
        $ipLocation = ip_location($ip);
        if ($ipLocation && !strstr($ipLocation, '保留地址')) {
            foreach (AreaConst::PROVINCES as $provAllowVal) {
                if (strstr($ipLocation, $provAllowVal)) {
                    $ipProvince = $provAllowVal;
                    break;
                }
            }
        }

        //$ipCity = $ipLocation ? trim(str_replace(['电信', '联通', '移动', '铁通', '教育网'], '', $ipLocation)) : '';
        $log['ip_province'] = $ipProvince;
        $log['ip_location'] = $ipLocation;
        // user_agent
        $userAgent = $log['user_agent'];
        /** @var Agent $agent */
        $agent = app(Agent::class);
        $agent->setUserAgent($userAgent);
        $platform = $agent->platform();
        $platformVersion = $agent->version($platform);
        $browser = $agent->browser();
        $browserVersion = $agent->version($browser);
        $log['platform'] = $platform ?: '';
        $log['platform_version'] = $platformVersion ?: '';
        $log['browser'] = $browser ?: '';
        $log['browser_version'] = $browserVersion ?: '';
    }

    /**
     * 保存日志属性数据
     * @param array $log
     */
    private static function saveLogAttrData(array $log): void {
        $create_time = $log['create_time'];
        $monthTableSuffix = date('Ym', $create_time);
        $logAttrModel = self::getAdminMemberLogAttrModel()->getSplitModel($monthTableSuffix);
        $lastData = $logAttrModel->getOwnRowToArray([['log_id', '=', $log['id']]]);

        if ($lastData) {
            // 更新
            $updateAttrData = [];
            if (!empty($log['request_params'])) $updateAttrData['request_params'] = $log['request_params'];
            if (!empty($log['response_content'])) $updateAttrData['response_content'] = $log['response_content'];
            if (!empty($log['desc'])) $updateAttrData['desc'] = $log['desc'];
            if ($updateAttrData) {
                $logAttrModel->change($updateAttrData, [['log_id', '=', $log['id']]]);
            }
            return;
        }
        // 新增
        $logAttrModel->addRow([
            'log_id' => $log['id'],
            'user_agent' => $log['user_agent'],
            'query_string' => $log['query_string'],
            'request_params' => !empty($log['request_params']) ? $log['request_params'] : '',
            'response_content' => !empty($log['response_content']) ? $log['response_content'] : '',
            'desc' => !empty($log['desc']) ? $log['desc'] : '',
        ], false);
    }

    /**
     * 保存日志基础数据
     * @param array $log
     */
    private static function saveLogData(array $log): void {
        $createTime = $log['create_time'];
        $monthTableSuffix = date('Ym', $createTime);
        $logModel = self::getAdminMemberLogModel()->getSplitModel($monthTableSuffix);
        $lastData = $logModel->getOwnRowToArray([['id', '=', $log['id']]]);
        if ($lastData) {
            // 更新
            $updateData = [];
            if (!empty($log['member_id'])) $updateData['member_id'] = $log['member_id'];
            if (!empty($log['data_id'])) $updateData['data_id'] = $log['data_id'];
            if ($updateData) {
                $logModel->change($updateData, [['id', '=', $log['id']]]);
            }
            return;
        }
        // 新增
        $logModel->addRow([
            'id' => $log['id'],
            'request_id' => $log['request_id'],
            'method' => $log['method'],
            'member_id' => $log['member_id'],
            'data_id' => $log['data_id'] ?? '',
            'ip' => $log['ip'],
            'ip_province' => $log['ip_province'],
            'ip_location' => $log['ip_location'],
            'platform' => $log['platform'],
            'platform_version' => $log['platform_version'],
            'browser' => $log['browser'],
            'browser_version' => $log['browser_version'],
            'create_time' => $createTime,
        ], false);
    }

    /**
     * 获取默认的data_id
     * @return string|int
     */
    private static function getDefaultDataId(array $allParams) {
        $data_id = '';
        foreach ($allParams as $k => $v) {
            if (!$v) continue;
            if ($k == 'id') {
                $data_id = $v;
                break;
            }
            if (!$data_id && ($k !== BuilderConst::ID_KEY && (substr($k, -3) === '_id' || substr($k, -2) === 'Id'))) {
                $data_id = $v;
            }
        }
        return $data_id;
    }

}